
import os
import json
from abc import abstractmethod
import pygame as pg
from . import constants as c

class State():
    def __init__(self):
        self.start_time = 0.0
        self.current_time = 0.0
        self.done = False
        self.next = None
        self.persist = {}
    
    @abstractmethod                             #装饰器定义了两个抽象方法
    def startup(self, current_time, persist):
        '''abstract method'''

    def cleanup(self):          #重置状态，并返回 persist 属性
        self.done = False
        return self.persist
    
    @abstractmethod
    def update(self, surface, keys, current_time):#抽象方法
        '''abstract method'''

class Control():                            #控制类
    def __init__(self):                     #初始化方法
        self.screen = pg.display.get_surface()#设定屏幕
        self.done = False
        self.clock = pg.time.Clock()#计时器
        self.fps = 60               #帧率，每秒60
        self.keys = pg.key.get_pressed()
        self.mouse_pos = None #定义鼠标位置
        self.mouse_click = [False, False]  # value:[left mouse click, right mouse click]，左右键的初始状态为False。
        self.current_time = 0.0#当前时间
        self.state_dict = {}    #游戏状态的空字典，设置初始状态
        self.state_name = None
        self.state = None
        self.game_info = {c.CURRENT_TIME:0.0,
                          c.LEVEL_NUM:c.START_LEVEL_NUM}

    def setup_states(self, state_dict, start_state):
        # 初始化状态字典、当前状态名称以及当前状态对象
        self.state_dict = state_dict
        self.state_name = start_state
        self.state = self.state_dict[self.state_name]
        # 初始化当前时间，并传递给当前状态的启动方法
        self.state.startup(self.current_time, self.game_info)

    def update(self):
        # 更新当前时间
        self.current_time = pg.time.get_ticks()
        # 检查当前状态是否完成
        if self.state.done:
            # 如果状态完成，切换到下一个状态
            self.flip_state()
        # 更新当前状态，传递屏幕、当前时间、鼠标位置和鼠标点击状态
        self.state.update(self.screen, self.current_time, self.mouse_pos, self.mouse_click)
        # 重置鼠标位置和点击状态
        self.mouse_pos = None
        self.mouse_click[0] = False
        self.mouse_click[1] = False

    def flip_state(self):
        # 存储先前的状态名称，并更新当前状态名称为下一个状态
        previous, self.state_name = self.state_name, self.state.next
        # 清理当前状态并获取任何持久化数据
        persist = self.state.cleanup()
        # 切换到下一个状态，并传递当前时间和持久化数据给其启动方法
        self.state = self.state_dict[self.state_name]
        self.state.startup(self.current_time, persist)

    def event_loop(self):                           #处理事件
        for event in pg.event.get():
            if event.type == pg.QUIT:               #鼠标点击关闭按钮，会触发事件监听
                self.done = True                    #触发这个后，游戏页面关闭
            elif event.type == pg.KEYDOWN:          #玩家按下键盘
                self.keys = pg.key.get_pressed()
            elif event.type == pg.KEYUP:            #玩家松开键盘
                self.keys = pg.key.get_pressed()
            elif event.type == pg.MOUSEBUTTONDOWN:  #鼠标按下
                self.mouse_pos = pg.mouse.get_pos()
                self.mouse_click[0], _, self.mouse_click[1] = pg.mouse.get_pressed()
                print('pos:', self.mouse_pos, ' mouse:', self.mouse_click)
                #pos和mouse输出鼠标在屏幕中点击的位置

    def main(self):
        while not self.done:
            # 不断循环，直到游戏标志变为True
            self.event_loop()
            # 处理事件
            self.update()
            # 更新游戏状态
            pg.display.update()
            # 刷新屏幕
            self.clock.tick(self.fps)
            # 控制游戏帧率
        print('game over')
        # 游戏结束时打印消息

def get_image(sheet, x, y, width, height, colorkey=c.BLACK, scale=1):
    # 获取从图像表单中提取的图像
    image = pg.Surface([width, height])
    rect = image.get_rect()

    image.blit(sheet, (0, 0), (x, y, width, height))
    # 从图像表单中提取子图像
    image.set_colorkey(colorkey)
    # 设置透明色
    image = pg.transform.scale(image,
                               (int(rect.width*scale),
                                int(rect.height*scale)))
    # 缩放图像
    return image

def load_image_frames(directory, image_name, colorkey, accept):
    # 加载一个文件夹中的所有图像帧
    frame_list = []
    tmp = {}
    index_start = len(image_name) + 1
    frame_num = 0;
    # 计算索引的起始位置和帧数
    for pic in os.listdir(directory):
        name, ext = os.path.splitext(pic)
        if ext.lower() in accept:
            index = int(name[index_start:])
            img = pg.image.load(os.path.join(directory, pic))
            if img.get_alpha():
                img = img.convert_alpha()
            else:
                img = img.convert()
                img.set_colorkey(colorkey)
            tmp[index]= img
            frame_num += 1

    for i in range(frame_num):
        frame_list.append(tmp[i])
    # 返回帧列表
    return frame_list

def load_all_gfx(directory, colorkey=c.WHITE, accept=('.png', '.jpg', '.bmp', '.gif')):
    # 加载所有的图像资源
    graphics = {}  # 5. 创建一个空字典来存储加载的图像资源
    for name1 in os.listdir(directory):  # 6. 遍历指定目录下的所有文件和文件夹
        dir1 = os.path.join(directory, name1)  # 7. 获取当前文件或文件夹的完整路径
        if os.path.isdir(dir1):  # 8. 判断是否是文件夹
            for name2 in os.listdir(dir1):  # 9. 遍历当前文件夹下的所有文件和文件夹
                dir2 = os.path.join(dir1, name2)  # 10. 获取当前文件或文件夹的完整路径
                if os.path.isdir(dir2):  # 11. 判断是否是文件夹
                    for name3 in os.listdir(dir2):  # 12. 遍历当前文件夹下的所有文件和文件夹
                        dir3 = os.path.join(dir2, name3)  # 13. 获取当前文件的完整路径
                        if os.path.isdir(dir3):  # 14. 判断是否是文件夹
                            image_name, _ = os.path.splitext(name3)  # 15. 获取文件名和扩展名
                            graphics[image_name] = load_image_frames(dir3, image_name, colorkey, accept)  # 16. 加载图像帧并存储到字典中
                        else:
                            image_name, _ = os.path.splitext(name2)  # 17. 获取文件名和扩展名
                            graphics[image_name] = load_image_frames(dir2, image_name, colorkey, accept)  # 18. 加载图像帧并存储到字典中
                            break  # 19. 结束当前循环
                else:
                    name, ext = os.path.splitext(name2)  # 20. 获取文件名和扩展名
                    if ext.lower() in accept:  # 21. 判断文件扩展名是否在可接受的范围内
                        img = pg.image.load(dir2)  # 22. 加载图像
                        if img.get_alpha():  # 23. 检查是否存在 alpha 通道
                            img = img.convert_alpha()  # 24. 转换为带 alpha 通道的图像
                        else:
                            img = img.convert()  # 25. 转换为不带 alpha 通道的图像
                            img.set_colorkey(colorkey)  # 26. 设置透明色
                        graphics[name] = img  # 27. 将图像存储到字典中
    return graphics  # 28. 返回加载的所有图像资源的字典

def loadZombieImageRect():
    file_path = os.path.join('source', 'data', 'entity', 'zombie.json')  # 29. 构建僵尸图像信息文件的完整路径
    f = open(file_path)  # 30. 打开文件
    data = json.load(f)  # 31. 加载 JSON 数据
    f.close()  # 32. 关闭文件
    return data[c.ZOMBIE_IMAGE_RECT]  # 33. 返回僵尸图像的矩形信息

def loadPlantImageRect():
    file_path = os.path.join('source', 'data', 'entity', 'plant.json')  # 34. 构建植物图像信息文件的完整路径
    f = open(file_path)  # 35. 打开文件
    data = json.load(f)  # 36. 加载 JSON 数据
    f.close()  # 37. 关闭文件
    return data[c.PLANT_IMAGE_RECT]  # 38. 返回植物图像的矩形信息

pg.init()  # 39. 初始化 Pygame
pg.display.set_caption(c.ORIGINAL_CAPTION)  # 40. 设置窗口标题
SCREEN = pg.display.set_mode(c.SCREEN_SIZE)  # 41. 创建游戏窗口

GFX = load_all_gfx(os.path.join("resources","graphics"))  # 42. 加载所有的图像资源
ZOMBIE_RECT = loadZombieImageRect()  # 43. 加载僵尸图像的矩形信息
PLANT_RECT = loadPlantImageRect()  # 44. 加载植物图像的矩形信息
